package com.chat.websocket.util.ip2region;

import lombok.extern.slf4j.Slf4j;
import org.lionsoul.ip2region.xdb.Searcher;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * SunJingxuan
 * 2022 \ 07 \ 28
 */
@Slf4j
@Component
public class Ip2regionUtil {

	@Value("${db.Path}")
	private String dbPath;

	public Map<String, Object> getIPTerritory(String ip) {


		// 1、从 dbPath 中预先加载 VectorIndex 缓存，并且把这个得到的数据作为全局变量，后续反复使用。
		byte[] vIndex;
		try {
			vIndex = Searcher.loadVectorIndexFromFile(dbPath);
		} catch (Exception e) {
			log.error("failed to load vector index from `{}`:", dbPath, e);
			return null;
		}

		// 2、使用全局的 vIndex 创建带 VectorIndex 缓存的查询对象。
		Searcher searcher;
		try {
			searcher = Searcher.newWithVectorIndex(dbPath, vIndex);
		} catch (Exception e) {
			log.error("failed to create vectorIndex cached searcher with `{}`: {}", dbPath, e);
			return null;
		}

		// 3、查询
		try {
			long sTime = System.nanoTime();
			String region = searcher.search(ip);
			long cost = TimeUnit.NANOSECONDS.toMicros((long) (System.nanoTime() - sTime));
			log.info("{region: {}, ioCount: {}, took: {} μs}", region, searcher.getIOCount(), cost);
			Map<String, Object> map = new HashMap<>();
			String[] split = region.split("\\|");
			map.put("region", region);
			map.put("country", split[0]);
			map.put("province", split[2]);
			map.put("city", split[3]);
			map.put("serviceProvider", split[4]);
			map.put("ioCount", searcher.getIOCount());
			map.put("took", cost + "μs");
			return map;
		} catch (Exception e) {
			log.error("failed to search({}): {}", ip, e);
		}
		return null;
		// 备注：每个线程需要单独创建一个独立的 Searcher 对象，但是都共享全局的制度 vIndex 缓存。
	}

	public String getIp() {
		RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
		String requestUrl = "";
		StringBuilder enumName = new StringBuilder();
		if (requestAttributes != null) {
			HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
			assert request != null;
			requestUrl = request.getRequestURL().toString();
			String[] requestUrlArr = requestUrl.split("/");
			enumName.append(requestUrlArr[3].toUpperCase()).append("_").append(requestUrlArr[4].replace("[A-Z]", "_$0").toUpperCase());
			String ip = request.getHeader("x-forwarded-for");
			if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("Proxy-Client-IP");
			}
			if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("WL-Proxy-Client-IP");
			}
			if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("HTTP_CLIENT_IP");
			}
			if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("HTTP_X_FORWARDED_FOR");
			}
			if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getRemoteAddr();
			}
			// 本机访问
			if ("localhost".equalsIgnoreCase(ip) || "127.0.0.1".equalsIgnoreCase(ip) || "0:0:0:0:0:0:0:1".equalsIgnoreCase(ip)) {
				// 根据网卡取本机配置的IP
				InetAddress inet;
				try {
					inet = InetAddress.getLocalHost();
					ip = inet.getHostAddress();
				} catch (UnknownHostException e) {
					log.error("未获取到ip地址", e);
				}
			}
			// 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
			if (null != ip && ip.length() > 15) {
				if (ip.indexOf(",") > 15) {
					ip = ip.substring(0, ip.indexOf(","));
				}
			}
			return ip;
		}
		return null;
	}
}
